﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using InvoiceInvoker.Logic;
using InvoiceInvoker.Logic.Repositories;

namespace InvoiceInvoker.MvcUI.Models
{
	public class InvoiceModel
	{
		[ScaffoldColumn(false)]
		public int Id { get; set; }

		[ScaffoldColumn(false)]
		public int RegisteredSellerId { get; set; }

		[ScaffoldColumn(false)]
		[DisplayName("Klient")]
		[Required(ErrorMessage = "Wybierz klienta")]
		[Range(1, int.MaxValue, ErrorMessage = "Wybierz klienta")]
		public int CustomerId { get; set; }

		[DisplayName("Klient")]
		[Required(ErrorMessage = "Wybierz klienta")]
		public CustomerModel Customer { get; set; }

		[DisplayName("Produkty")]
		public List<Product> Products { get; set; }

		[DisplayName("Numer faktury")]
		[Required(ErrorMessage = "Podaj numer faktury")]
		[StringLength(50, ErrorMessage = "Numer faktury może mieć co najwyżej 50 znaków")]
		public string Number { get; set; }

		[DisplayName("Data wystawienia")]
		[Required(ErrorMessage = "Wybierz datę wystawienia faktury")]
		public DateTime CreationDate { get; set; }

		[DisplayName("Data sprzedaży")]
		[Required(ErrorMessage = "Wybierz datę sprzedaży")]
		public DateTime SaleDate { get; set; }

		[DisplayName("Sposób płatności")]
		[Required(ErrorMessage = "Wybierz sposób płatności")]
		[StringLength(10, ErrorMessage = "Sposób płatności może mieć co najwyżej 10 znaków")]
		public string PaymentType { get; set; }

		[DisplayName("Termin płatności")]
		[Required(ErrorMessage = "Wybierz termin płatności")]
		public DateTime PaymentDeadline { get; set; }

		[DisplayName("Waluta")]
		[Required(ErrorMessage = "Podaj walutę")]
		[StringLength(10, ErrorMessage = "Waluta może mieć co najwyżej 10 znaków")]
		public string PaymentCurrency { get; set; }

		[DisplayName("Razem do zapłaty")]
		[Range(0, (double)decimal.MaxValue, ErrorMessage = "Kwota do zapłaty musi być większa lub równa 0")]
		public decimal ToPay { get; set; }

		[DisplayName("Słownie do zapłaty")]
		[Required(ErrorMessage = "Podaj słownie kwotę do zapłaty")]
		[StringLength(3000, ErrorMessage = "Kwota słownie może mieć co najwyżej 3000 znaków")]
		public string ToPayInWords { get; set; }

		[DisplayName("Zapłacono")]
		[Range(0, (double)decimal.MaxValue, ErrorMessage = "Kwota zapłacona musi być większa lub równa 0")]
		public decimal Paid { get; set; }

		[DisplayName("Pozostało do zapłaty")]
		[Range(0, (double)decimal.MaxValue, ErrorMessage = "Kwota pozostała do zapłaty musi być większa lub równa 0")]
		public decimal LeftToPay { get; set; }

		[DisplayName("Uwagi")]
		[StringLength(3000, ErrorMessage = "Uwagi mogą mieć co najwyżej 3000 znaków")]
		public string Remarks { get; set; }

		[DisplayName("Status")]
		[StringLength(20, ErrorMessage = "Status może mieć co najwyżej 20 znaków")]
		public string Status { get; set; }

		public InvoiceModel()
		{
			Customer = new CustomerModel();
			Products = new List<Product>();
		}

		public InvoiceModel(int registeredSellerId)
		{
			RegisteredSellerId = registeredSellerId;

			Customer = new CustomerModel();
			Products = new List<Product>();

			RegisteredSeller seller = new RegisteredSellerRepository().GetById(registeredSellerId);
			Number = new InvoiceNumber(seller.LastInvoiceNumber, seller.InvoiceNumberFormat).GetNext().ToString();

			CreationDate = DateTime.Today;
			SaleDate = DateTime.Today;
			PaymentDeadline = DateTime.Today.AddDays(14);

			PaymentCurrency = "PLN";

			Status = Invoice.InvoiceStatus.Created.ToString();
		}

		public InvoiceModel(Invoice invoice)
		{
			Id = invoice.Id;
			RegisteredSellerId = invoice.RegisteredSellerId ?? 0;
			Customer = new CustomerModel(invoice.Customer);
			CustomerId = invoice.CustomerId ?? 0;
			Number = invoice.Number;
			CreationDate = invoice.CreationDate ?? new DateTime();
			SaleDate = invoice.SaleDate ?? new DateTime();
			PaymentType = invoice.PaymentType;
			PaymentDeadline = invoice.PaymentDeadline ?? new DateTime();
			PaymentCurrency = invoice.PaymentCurrency;
			ToPay = invoice.ToPay ?? 0;
			ToPayInWords = invoice.ToPayInWords;
			Paid = invoice.Paid ?? 0;
			LeftToPay = invoice.LeftToPay ?? 0;
			Remarks = invoice.Remarks;
			Status = invoice.Status;

			Products = new List<Product>();
			foreach (var product in invoice.Products)
				Products.Add(product);

			Products.Sort((a, b) => a.Name.CompareTo(b.Name));
		}

		public InvoiceModel(InvoicePattern invoicePattern)
		{
			RegisteredSellerId = invoicePattern.RegisteredSellerId ?? 0;
			Customer = new CustomerModel(invoicePattern.RegisteredCustomer);
			CustomerId = Customer.Id;

			RegisteredSeller seller = new RegisteredSellerRepository().GetById(RegisteredSellerId);
			Number = new InvoiceNumber(seller.LastInvoiceNumber, seller.InvoiceNumberFormat).GetNext().ToString();

			CreationDate = DateTime.Today;
			SaleDate = DateTime.Today;
			PaymentDeadline = DateTime.Today.AddDays(14);

			PaymentType = invoicePattern.PaymentType;
			PaymentCurrency = invoicePattern.PaymentCurrency;

			Remarks = invoicePattern.Remarks;

			Status = Invoice.InvoiceStatus.Created.ToString();

			Products = new List<Product>();
			foreach (var item in invoicePattern.InvoicePatternRegisteredProducts)
				Products.Add(item.RegisteredProduct.ToProduct(1, true));

			Products.Sort((a, b) => a.Name.CompareTo(b.Name));
		}

		public Invoice ToInvoice(List<int> productIds, Dictionary<int, decimal> productQuantities)
		{
			Invoice result = new Invoice();
			result.RegisteredSellerId = RegisteredSellerId;
			result.Customer = new RegisteredCustomerRepository(RegisteredSellerId).GetById(CustomerId).ToCustomer();
			result.Number = Number;
			result.CreationDate = CreationDate;
			result.SaleDate = SaleDate;
			result.PaymentType = PaymentType;
			result.PaymentDeadline = PaymentDeadline;
			result.PaymentCurrency = PaymentCurrency;
			result.ToPay = ToPay;
			result.ToPayInWords = ToPayInWords;
			result.Paid = Paid;
			result.LeftToPay = LeftToPay;
			result.Remarks = Remarks;
			result.Status = Status;

			RegisteredProductRepository productRepository = new RegisteredProductRepository(RegisteredSellerId);
			foreach (int id in productIds)
				result.Products.Add(productRepository.GetById(id).ToProduct(productQuantities[id]));

			return result;
		}
	}
}